#include <psp2/kernel/processmgr.h>
#include <psp2/io/fcntl.h>
#include <sstream>
#include <vector>

#include <cstdio>

//#include <debugScreen.h>

//#include "s3e.h"
//#include <GL/gl.h>
#include <vitaGl.h>			//Ideaworks GL
#include "gameswf/gameswf.h"
#include <stdlib.h>
#include <stdio.h> 
#include <iostream>
#include <stdarg.h>
#include <psp2/touch.h>

#include "base/utility.h"
#include "base/container.h"
#include "base/tu_file.h"
#include "base/tu_types.h"
#include "base/tu_timer.h"
#include "gameswf/gameswf_types.h"
#include "gameswf/gameswf_impl.h"
#include "gameswf/gameswf_root.h"
#include "gameswf/gameswf_freetype.h"
#include "gameswf/gameswf_player.h"
#include "string.h"

//#include "gameswf_render_handler_iwgl.cpp"
#include <psp2common/kernel/iofilemgr.h>
using namespace std;
#define LOG_PATH  DATA_PATH "log.txt"
#define OVERSIZE	1.0f
#define SwfGame DATA_PATH "start.swf"
#define printf psvDebugScreenPrintf
#define SCREEN_W 960
#define SCREEN_H 544
#define GL_LINE_SMOOTH 0x0B20
#define GL_LINE_SMOOTH_HINT	0x0C52
int lastX[2] = { -1, -1 };
int lastY[2] = { -1, -1 };

static tu_file*	file_opener(const char* url)
// Callback function.  This opens files for the gameswf library.
{
	return new tu_file(url, "rb");
}

int debugPrintf(const char *text, ...)
{
#ifdef _DEBUG
    va_list list;
    char string[4096];

    va_start(list, text);
    vsprintf(string, text, list);
    va_end(list);
    //printf("%s", string);

    SceUID fd = sceIoOpen(LOG_PATH, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_APPEND, 0777);
    if (fd >= 0)
    {
        int len=strlen(string);
        string[len]='\n';
        sceIoWrite(fd, string, len+1);
        sceIoClose(fd);
    }
#endif
    return 0;
}

void GameSWF_log_handler (bool error, const char* message)
{
//    NSLog(@"%@: %s", (error ? @"::ERROR: " : @":::: "), message);
    if (error) {
        //CCLOG("::ERROR:: %s",message);
		debugPrintf(message);
    }else{
        //CCLOG(":::: %s",message);
    }
}

void GLInit() {
    vglInitExtended(0, SCREEN_W, SCREEN_H, 6 * 1024 * 1024, SCE_GXM_MULTISAMPLE_4X);
}

void GLSwapBuffers() {
    vglSwapBuffers(GL_FALSE);
}

void Controls(gameswf::gc_ptr<gameswf::root> m)
{
	SceTouchData touch;
    sceTouchPeek(SCE_TOUCH_PORT_FRONT, &touch, 1);

    for (int i = 0; i < 2; i++) {
        if (i < touch.reportNum) {
            int x = (int)((float)touch.report[i].x * (float)SCREEN_W / 1920.0f);
            int y = (int)((float)touch.report[i].y * (float)SCREEN_H / 1088.0f);

            if (lastX[i] == -1 || lastY[i] == -1) {
                //sceClibPrintf("touchdown x %i y %i \n", x, y);
				m->notify_mouse_state(x,y,1);
            }
            else if (lastX[i] != x || lastY[i] != y)
			    m->notify_mouse_state(x,y,2);
            lastX[i] = x;
            lastY[i] = y;
        } else {
            if (lastX[i] != -1 || lastY[i] != -1)
			    m->notify_mouse_state(lastX[i],lastY[i],0);
            lastX[i] = -1;
            lastY[i] = -1;
        }
    }
}

void RenderUpData(gameswf::gc_ptr<gameswf::player> player,gameswf::gc_ptr<gameswf::root> m)
{
	m = player->get_root();
	m->set_display_viewport(0, 0, SCREEN_W, SCREEN_H);
	m->set_background_alpha(1.0f);
	//s3ePointerUpdate();
	//m->notify_mouse_state(s3ePointerGetX	() 	, s3ePointerGetY	(), s3ePointerGetTouchState	(0));
	Controls(m);
	m->advance(50);
	m->display(NULL);
}


int main_thread(SceSize args, void *argp)
{
	debugPrintf("main_thread start\n");
	gameswf::render_handler*	render = NULL;
	gameswf::register_log_callback(&GameSWF_log_handler);

	GLInit();
	
	gameswf::gc_ptr<gameswf::player> player = new gameswf::player();
	player->verbose_action(true);
	player->verbose_parse(true);
	player->set_separate_thread(false);
	player->set_log_bitmap_info(true);

	debugPrintf("create render start\n");
	render =  gameswf::create_render_handler_iwgl();
	//render =  gameswf::create_render_handler_ogles();
	debugPrintf("create render end\n");

	gameswf::set_render_handler(render);
	
	gameswf::register_file_opener_callback(file_opener);
	debugPrintf("load file start\n");
	gameswf::gc_ptr<gameswf::root>	m = player->load_file(SwfGame);
	if (m == NULL)
	{
		exit(1);
	}

	int fpsLock=m->get_movie_fps();
	if (fpsLock > 0 && fpsLock <= 30)
        eglSwapInterval(0, 2);

	render->open();

	render->set_antialiased(true);

	// Turn on alpha blending.
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
	// Turn on line smoothing.  Antialiased lines can be used to
	// smooth the outsides of shapes.
	glEnable(GL_LINE_SMOOTH);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);	// GL_NICEST, GL_FASTEST, GL_DONT_CARE
	
	glMatrixMode(GL_PROJECTION);
	
	//TODO pete - glOrtho not defined?
	//glOrtho(-OVERSIZE, OVERSIZE, OVERSIZE, -OVERSIZE, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	// We don't need lighting effects
	glDisable(GL_LIGHTING);
	// glColorPointer(4, GL_UNSIGNED_BYTE, 0, *);
	// glInterleavedArrays(GL_T2F_N3F_V3F, 0, *)
	
	//TODO - pete GL_ALL_ATTRIB_BITS not defined?
	//glPushAttrib (GL_ALL_ATTRIB_BITS);
	
	
	glDisable(GL_DEPTH_TEST);	// Disable depth testing.
	//glDrawBuffer(GL_BACK);
	
	//gameswf::gc_ptr<gameswf::player> player = ((gameswf::player*)argp);
	//gameswf::gc_ptr<gameswf::root> m = player->get_root();
	debugPrintf("main_thread while start\n");

	// while (1) {
	// 	//controls_poll();
	// 	RenderUpData(player,m);
	// 	GLSwapBuffers();
	// }
	// return 0;
	// if (fpsLock == 0 || fpsLock == 30) {
    //     while (1) {
    //         //controls_poll();
    //         RenderUpData(player,m);
	// 		GLSwapBuffers();
    //     }
    // }
	// else {
        uint32_t last_render_time = sceKernelGetProcessTimeLow();
        uint32_t delta = (1000000 / (fpsLock+1));

        while (1) {
            //controls_poll();
            RenderUpData(player,m);

            while (sceKernelGetProcessTimeLow() - last_render_time < delta) {
                sched_yield();
            }

            last_render_time = sceKernelGetProcessTimeLow();

			GLSwapBuffers();
        }
    //}
    debugPrintf("main_thread over \n");
	return 0;
}

int main(int argc, char *argv[]) {
	// std::stringstream output;
	// std::vector<std::string> hello = { "Hello" };
	// hello.push_back(",");
	// hello.push_back(" C++ ");
	// hello.push_back("world!");
	// for (auto &s : hello) {
	// 	// std::cout does't work ATM :(
	// 	output << s;
	// }
	// output << std::endl;
	// psvDebugScreenInit();
	// printf("%s\n", output.str().c_str());
	
	debugPrintf("main start");

	SceUID thid = sceKernelCreateThread("main_thread", (SceKernelThreadEntry)main_thread, 0x40,2* 128 * 1024, 0, 0, NULL);
	sceKernelStartThread(thid, 0, NULL);
	// sceKernelDelayThread(4*1000000); // Wait for 3 seconds
	// sceKernelExitProcess(0);
	//delete player;
	
	return sceKernelExitDeleteThread(0);
    //return 0;
}
